#include <nxos.h>
#include <winbuf/winbuf.h>

#if CONFIG_WINBUF_TEST == 1
NX_PRIVATE NX_Error test_winbuf1(void)
{
    NX_Error err;
    Winbuf * wb;
    NX_U32 colorArr[8] = {
        WINBUF_RED,
        WINBUF_GREEN,
        WINBUF_BLUE,
        WINBUF_WHITE,
        WINBUF_BLACK,
        WINBUF_GRAY,
        WINBUF_LEAD,
        WINBUF_YELLOW,
    };
    int colorIdx;

    if ((err = WinbufInit()) != NX_EOK)
    {
        NX_Printf("init win buf failed with %s!\n", NX_ErrorToString(err));
        return NX_ERROR;    
    }

    wb = CreateWinbuf(GetBaseWinbufWidth(), GetBaseWinbufHeight());
    if (wb == NX_NULL)
    {
        NX_Printf("create win buf failed!\n");
        return NX_ENOMEM;
    }

    NX_Printf("create winbuf ok\n");

    DrawRectWinbuf(wb, NX_NULL, WINBUF_RED);
    NX_Printf("draw winbuf ok\n");

    if ((err = TopWinbuf(wb)) != NX_EOK)
    {
        NX_Printf("top winbuf failed!");
        return err;
    }
    
    NX_Printf("start loop\n");

    colorIdx = 0;
    while (1)
    {
        NX_U32 color = colorArr[colorIdx++];
        colorIdx %= 8;
        NX_ThreadSleep(20);
        Winbuf * new_wb = CreateWinbuf(50 * (1 + colorIdx), 50 * (1 + colorIdx));
        if (new_wb == NX_NULL)
        {
            NX_Printf("create win buf failed!\n");
            return NX_ENOMEM;
        }

        DrawRectWinbuf(new_wb, NX_NULL, color);
        SetWinbufPostion(new_wb, -100 + 50 * (1 + colorIdx), -100 + 50 * (1 + colorIdx));
        
        if ((err = TopWinbuf(new_wb)) != NX_EOK)
        {
            NX_Printf("top winbuf failed!");
            return err;
        }
        int i = 0;
        while (i < 8)
        {
            NX_U32 color = colorArr[colorIdx++];
            colorIdx %= 8;
            DrawRectWinbuf(new_wb, NX_NULL, color);
            FlushWinbuf(new_wb, NX_NULL);
            i++;
            NX_ThreadSleep(20);
        }
        DestroyWinbuf(GetTopWinbuf());
        TopWinbuf(GetTopWinbuf());
    }
    return NX_EOK;
}

NX_PRIVATE NX_U32 thread(void *arg)
{
    Winbuf * wb;
    NX_U32 tid = NX_ThreadGetCurrentId();

    wb = CreateWinbuf(GetBaseWinbufWidth(), GetBaseWinbufHeight());
    if (wb == NX_NULL)
    {
        NX_Printf("create win buf failed!\n");
        return NX_ENOMEM;
    }
    
    NX_TimeVal time1 = 0;
    NX_TimeVal time2 = 0;
    int fps = 0;
    
    time1 = NX_ClockGetMillisecond();
    
    while (1)
    {
        fps++;
        time2 = NX_ClockGetMillisecond();
        unsigned long long mtime = (time2 - time1);
        if (mtime > 1000) {
            NX_Printf("thread %d fps %d\n", tid, fps);
            fps = 0;
            time1 = time2;
        }
    
        DrawRectWinbuf(wb, NX_NULL, WINBUF_RGB(tid * 20, tid * 10, tid * 50));
        TopWinbuf(wb);
    }
    
}

NX_PRIVATE NX_Error test_winbuf2(void)
{
    NX_Error err;
    int i;

    if ((err = WinbufInit()) != NX_EOK)
    {
        NX_Printf("init win buf failed with %s!\n", NX_ErrorToString(err));
        return err;    
    }

    for (i = 0; i < 32; i++)
    {
        NX_ThreadCreate(NX_NULL, thread, NX_NULL, 0, NX_NULL);
    }

    while (1)
    {
        NX_ThreadSleep(1000);
    }    

    return NX_EOK;
}

NX_PRIVATE NX_U32 client_thread(void *arg)
{
    Winbuf * wb;
    NX_U32 code;
    NX_U32 kmod;
    int mx, my;
    int wheel;
    
    wb = CreateWinbuf(GetBaseWinbufWidth(), GetBaseWinbufHeight());
    if (wb == NX_NULL)
    {
        NX_Printf("create win buf failed!\n");
        return NX_ENOMEM;
    }

    DrawRectWinbuf(wb, NX_NULL, WINBUF_RED);

    TopWinbuf(wb);
    
    WinbufMsg m;
    while (1)
    {
        if (GetWinbufMsg(wb, &m) == NX_EOK)
        {
            switch (GetWinbufMsgId(&m))
            {
            case WINBUF_MSG_KEY_DOWN:
                code = GetWinbufMsgCode(&m);
                kmod = GetWinbufMsgKeyModify(&m);
                NX_Printf("key down: code %x/%c mod:%x\n", code, code, kmod);
                break;

            case WINBUF_MSG_KEY_UP:
                code = GetWinbufMsgCode(&m);
                kmod = GetWinbufMsgKeyModify(&m);
                NX_Printf("key up: code %x/%c mod:%x\n", code, code, kmod);
                break;
            
            case WINBUF_MSG_MOUSE_MOTION:
                mx = GetWinbufMsgX(&m);
                my = GetWinbufMsgY(&m);
                NX_Printf("mouse motion: (%d, %d)\n", mx, my);
                break;
            case WINBUF_MSG_MOUSE_WHEEL_UP:
                mx = GetWinbufMsgX(&m);
                my = GetWinbufMsgY(&m);
                wheel = GetWinbufMsgWheel(&m);
                NX_Printf("mouse wheel up: (%d, %d) %d\n", mx, my, wheel);
                break;
            case WINBUF_MSG_MOUSE_WHEEL_DOWN:
                mx = GetWinbufMsgX(&m);
                my = GetWinbufMsgY(&m);
                wheel = GetWinbufMsgWheel(&m);
                NX_Printf("mouse wheel down: (%d, %d) %d\n", mx, my, wheel);
                break;
            case WINBUF_MSG_MOUSE_LBTN_DOWN:
                mx = GetWinbufMsgX(&m);
                my = GetWinbufMsgY(&m);
                NX_Printf("mouse left btn down: (%d, %d)\n", mx, my);
                break;
            case WINBUF_MSG_MOUSE_LBTN_UP:
                mx = GetWinbufMsgX(&m);
                my = GetWinbufMsgY(&m);
                NX_Printf("mouse left btn up: (%d, %d)\n", mx, my);
                break;
                
            case WINBUF_MSG_MOUSE_MBTN_DOWN:
                mx = GetWinbufMsgX(&m);
                my = GetWinbufMsgY(&m);
                NX_Printf("mouse middle btn down: (%d, %d)\n", mx, my);
                break;
            case WINBUF_MSG_MOUSE_MBTN_UP:
                mx = GetWinbufMsgX(&m);
                my = GetWinbufMsgY(&m);
                NX_Printf("mouse middle btn up: (%d, %d)\n", mx, my);
                break;
                
            case WINBUF_MSG_MOUSE_RBTN_DOWN:
                mx = GetWinbufMsgX(&m);
                my = GetWinbufMsgY(&m);
                NX_Printf("mouse right btn down: (%d, %d)\n", mx, my);
                break;
            case WINBUF_MSG_MOUSE_RBTN_UP:
                mx = GetWinbufMsgX(&m);
                my = GetWinbufMsgY(&m);
                NX_Printf("mouse right btn up: (%d, %d)\n", mx, my);
                break;
            
            default:
                NX_Printf("unknown msg: %d\n", GetWinbufMsgId(&m));
                break;
            }
        }
    }
}

NX_PRIVATE NX_Error test_winbuf3(void)
{
    NX_Error err;

    if ((err = WinbufInit()) != NX_EOK)
    {
        NX_Printf("init win buf failed with %s!\n", NX_ErrorToString(err));
        return err;
    }

    /* create client thread */
    NX_ThreadCreate(NX_NULL, client_thread, NX_NULL, 0, NX_NULL);

    WinbufLoop();
    
    return NX_EOK;
}

void WinbufTest(void)
{
#if CONFIG_WINBUF_TEST_BUF == 1
    test_winbuf1();
#endif
#if CONFIG_WINBUF_TEST_DRAW == 1
    test_winbuf2();
#endif
#if CONFIG_WINBUF_TEST_MSG == 1
    test_winbuf3();
#endif
}
#endif
